package gbench.appdemo.mall.erp.components;

import static gbench.common.matlib.MatlibCanvas.println;
import static gbench.common.tree.LittleTree.IRecord.REC;
import static gbench.common.tree.LittleTree.Term.FT;

import java.time.LocalDateTime;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

import gbench.common.tree.LittleTree.IRecord;
import gbench.common.tree.LittleTree.SQL;

/**
 * 
 * @author gbench
 *
 */
public interface ICatalog extends IMyERPEntity {
    
    /**
     * 
     * @return
     */
    public Integer getId();

    /**
     * 名称
     * 
     * @return
     */
    public String getName();
    
    public ICatalog setAttributes(final IRecord attributes);

    /**
     * @return the attributes
     */
    public IRecord getAttributes();

    /**
     * 返回产品价格流
     * 
     * @param <T>    结果元素类型
     * @param mapper 元素变化函数 priceQuote->t
     * @return 产品价格流
     */
    public <T> Stream<T> stream(final Function<IPriceQuote, T> mapper);

    /**
     * catalog 的产品变换
     * 
     * @param <U> 结果类型
     * @param collector 归集器
     * @return U 产品表的归集项目
     */
    public <U> U collect(Collector<? super IPriceQuote, ?, U> collector);

    /**
     * 获取报价清单
     * @return 报价清单
     */
    public default Stream<IRecord> getQuoteS(){
        final var dataApp = this.dataApp();
        final var sql = FT("select * from t_entity_item_rel where name='t_product/t_money' and optional='$0'",this.getId());
        final var _sql = FT("select a.entity_id id, b.name, b.price baseprice, a.quantity price, "
            + "b.money,a.amount ratio, a.description, a.id offerid, drcr ownerid, a.path url "
            + "from ($0) a inner join t_product b on a.entity_id = b.id",sql);
        
        return dataApp.sqlqueryS(_sql);
    }
    
    /**
     * 获取产品报价
     * 
     * @return 产品报价
     */
    public default Stream<IPriceQuote> getPriceQuoteS(){
        return this.getPriceQuotes().stream();
    }
    
    /**
     * 获取产品报价
     * 
     * @return 产品报价
     */
    public default List<IPriceQuote> getPriceQuotes(){
        final var erpApp = this.erpApp();
        final var financeApp = this.erpApp().financeApp();
        return this.getQuoteS().map(e -> {
            final var productId = e.i4("id");
            final var pct = this.erpApp().productOf(productId); // 提取产品id
            final var price = financeApp.rmb(e.dbl("price"));
            final var priceQuote = erpApp.priceQuoteOf(pct, price).setAttributes(e);// 设置报价属性信息
            return priceQuote;
        }).collect(Collectors.toList());
    }

    /**
     * 属主id
     * @return 属主id
     */
    public default Integer getOwnerId() {
        
        final var attributes = this.getAttributes();
        
        final var ownerid = attributes == null ? null : attributes.i4("ownerid");
        
        return ownerid;
    }
    
    /**
     * 保存为价格目录
     * 
     * @param ownerId    产品目录的所有者id
     * @param quoteItems 产品报价 [{product,price,tax}]
     * 
     * @return Catalog 本身
     */
    public default ICatalog add(final Iterable<IRecord> quoteItems) {
        final Integer ownerId = this.getOwnerId();
        final var dataApp = this.dataApp();
        final var erpApp = this.erpApp();
        
        if (ownerId == null) {
            System.err.println(FT("无法获得属主id,catalog 无效：$0", this.getAttributes()));
        } else {
            final var owner  = erpApp.getEnterprise(this.getOwnerId());// 提取owenr 对象
            dataApp.withTransaction(sess -> {
                for( var quoteItem:quoteItems){ // 把产品价格加入到 产品目录。
                    final var pct = quoteItem.get("product", IProduct.class);
                    final var price = quoteItem.dbl("price", pct.getPrice().getAmount());
                    final var tax = quoteItem.dbl("tax", 0.17);
                    final var pricequote_sql = SQL.of("t_entity_item_rel", REC("name", "t_product/t_money", 
                        "entity_id", pct.getId(), "item_id", 1, "optional", this.getId(), "drcr", ownerId) // item_id 对应于 moneyid
                    ); // 检查价格目录的产品项目是否存在,optional为价格目录编号,entity_id 对应产品id
                    
                    final var opt = sess.sql2maybe(pricequote_sql.select()); // 检查 pricequote 是否存在
                    // println(opt);
                    if (opt.isEmpty()) { // 加入报价单
                        final var create_time = LocalDateTime.now();
                        // 报价单的创建 其中 amount 是作为 税率来出现的
                        final var rec = REC(
                            "name", "t_product/t_money", "path", "D:/sliced/files/products/valuables/gold.jpg", // 明细记录
                            /* 产品id */ "entity_id", pct.getId(), /* 货币id */ "item_id", 1,
                            /* 产品报价 */ "quantity", price, /* 有效标记 */"flag", 0, /* 产品税率 */ "amount", tax,
                            /* 价格目录编号 */ "optional", this.getId(), /* 所有者id */ "drcr", ownerId,
                            /* 有效标记 */"flag", 0, /* 价格目录说明 */"description", pct.getName(),
                            "create_time",create_time
                        ); // rec
                        final var sql = SQL.of("t_entity_item_rel",rec).insert();
                        sess.sql2execute(sql);
                    } else { // 
                        println(FT("$0-$1",owner.getName(),this.getName()),"add",quoteItem, "已经存在");
                    } // if
                } // 价格目录制作
            }); // withTransaction
        } // if
        
        return this;
    }

    /**
     * 从价格表目录中删除产品
     * 
     * @param catalogId    产品目录的所有者id
     * @param quoteItems [产品列表]
     * @return Catalog 本身
     */
    public default ICatalog remove(final Iterable<IProduct> quoteItems) {
        final var dataApp = this.dataApp();
        final var catalogId = this.getId();
        final var ids = StreamSupport.stream(quoteItems.spliterator(), false).map(e->e.getId()+"").collect(Collectors.joining(","));
        // entity_id 对应产品id, item_id 对应货币id
        final var sql  = FT("delete from t_entity_item_rel where optional=$0 and name='t_product/t_money' and entity_id in ($1)",catalogId,ids);
        
        dataApp.withTransaction(sess -> {
            sess.sql2execute(sql);
        });
        
        return this;
    }
    
    /**
     * 从价格表目录中更新产品
     * 
     * @param catalogId  产品目录的所有者id
     * @param quoteItems 产品报价 [{product,price,tax}]，对于未出现在先前产品项中的新产品给予添加
     * @return Catalog 本身
     */
    public default ICatalog update(final Iterable<IRecord> quoteItems) {
        
        final var dataApp = this.dataApp();
        final var catalogId = this.getId();
        final var sql = FT("select * from t_entity_Item_rel where name='t_fortune/t_catalog' and item_id=$0",catalogId); // 检查catalog是否存在
        final var catalog_opt = dataApp.sql2maybe(sql);
        if (catalog_opt.isPresent()) {
            final Integer ownerId = catalog_opt.map(e->e.i4("entity_id")).get(); // entity_id  对应owner id
            dataApp.withTransaction(sess -> {
                for (final var quoteItem : quoteItems) {
                    
                    final var pct = quoteItem.get("product", IProduct.class);
                    if (pct == null) continue;
                    
                    final var price = quoteItem.dbl("price", pct.getPrice().getAmount());
                    final var tax = quoteItem.dbl("tax", 0.17);
                    final var item_opt = dataApp.rel2maybe_rec_f("t_product", "t_money").apply(REC(
                        "entity_id", pct.getId(), "item_id", 1, "optional", this.getId())  // item_id 对应于 moneyid
                    ); // 检查价格目录的产品项目是否存在,optional为价格目录编号,entity_id 对应产品id
                    if(item_opt.isPresent()) {
                        final var upt_time = LocalDateTime.now();
                        final var where = FT("name ='t_product/t_money' and optional=$0 and entity_id=$1",this.getId(),pct.getId());
                        final var upt_sql  = FT("update t_entity_Item_rel set quantity=$0,amount=$1,update_time='$2' where $3",
                                price,tax,upt_time,where);// quantity 对应 price, amount 对应 tax
                        //println(upt_sql);
                        sess.sqlexecute(upt_sql);
                    } else {// 新创建
                        final var create_time = LocalDateTime.now();
                        final var rec = REC(
                            "path", "D:/sliced/files/products/valuables/gold.jpg","name","t_product/t_money", // 产品项表头
                            /* 产品id */ "entity_id", pct.getId(), /* 货币id */ "item_id", 1,
                            /* 产品报价 */ "quantity", price, /* 有效标记 */"flag", 0, /* 产品税率 */ "amount", tax,
                            /* 价格目录编号 */ "optional", this.getId(), /* 所有者id */ "drcr", ownerId,
                            /* 有效标记 */"flag", 0, /* 价格目录说明 */"description", pct.getName(),
                            "create_time",create_time
                        );
                       
                        final var ins_sql = SQL.of("t_entity_item_rel", rec).insert();
                        //println(ins_sql);
                        sess.sql2execute(ins_sql);
                    }// if
                }// for
            }); // withTransaction
        } else {
            System.err.print(FT("catalog $0 不存在无法更新",this.getId()));
        } // if
        
        return this;
    }

}
